#include "com_andon_colbert_ffplayer_FFPlayer.h"

// 生产线程
pthread_t p_tid;
// 音频流
FAudio *fAudio;
// 视频流
FVideo *fVideo;
// 解封装上下文
AVFormatContext *frtCtx;
// 是否正在播放
int isPlaying;
// 绘制窗体
ANativeWindow *window;

JNIEXPORT void JNICALL Java_com_andon_colbert_ffplayer_FFPlayer_play
        (JNIEnv *env, jobject clazz, jstring j_path) {
    const char *path = env->GetStringUTFChars(j_path, NULL);
    env->ReleaseStringUTFChars(j_path, path);
    // 初始化音视频
    fVideo = new FVideo;
    fVideo->fAudio = fAudio = new FAudio;
    // 开启解封装（生产者）线程
    isPlaying = 1;
    pthread_create(&p_tid, NULL, play, (void *) path);
}

// 播放
void *play(void *url) {
    // 注册所有组件
    av_register_all();
    // 初始化网络
    avformat_network_init();

    frtCtx = avformat_alloc_context();
    // 打开视频
    int rs = avformat_open_input(&frtCtx, (const char *) url, NULL, NULL);
    if (rs != 0) {
        LOG_E("打开视频失败，errorCode: %d", rs);
        return 0;
    }
    // 查找流信息
    rs = avformat_find_stream_info(frtCtx, NULL);
    if (rs < 0) {
        LOG_E("解析流信息失败，errorCode: %d", rs);
        return 0;
    }
    // 遍历流信息，查找音视频流
    int i = 0;
    for (; i < frtCtx->nb_streams; i++) {
        AVCodecContext *codecCtx = frtCtx->streams[i]->codec;
        // 查找解码器
        AVCodec *codec = avcodec_find_decoder(codecCtx->codec_id);
        if (codec == NULL) {
            continue;
        }
        // 找到音频流
        if (codecCtx->codec_type == AVMEDIA_TYPE_AUDIO) {
            // 打开解码器
            rs = avcodec_open2(codecCtx, codec, NULL);
            if (rs < 0) {
                LOG_E("打开音频解码器失败，errorCode: %d", rs);
                return 0;
            }
            fAudio->setCodecContext(codecCtx, i);
            fAudio->time_base = frtCtx->streams[i]->time_base;
        }
        // 找到视频流
        if (codecCtx->codec_type == AVMEDIA_TYPE_VIDEO) {
            // 打开解码器
            rs = avcodec_open2(codecCtx, codec, NULL);
            if (rs < 0) {
                LOG_E("打开视频解码器失败，errorCode: %d", rs);
                return 0;
            }
            fVideo->setCodecContext(codecCtx, i);
            fVideo->time_base = frtCtx->streams[i]->time_base;
            if (window) {
                fVideo->setANativeWindow(window);
            }
        }
    }
    // 开启（消费者）线程，播放音视频
    fAudio->play();
    fVideo->play();
    // 开始解封装音视频流
    AVPacket *packet = (AVPacket *) av_mallocz(sizeof(AVPacket));
    while (isPlaying) {
        int ret = av_read_frame(frtCtx, packet);
        if (ret == 0) {
            // 循环读取每一帧
            if (packet->stream_index == fAudio->stream_idx) {
                // 读取到音频帧
                fAudio->push(packet);
            }
            if (packet->stream_index == fVideo->stream_idx) {
                // 读取到视频帧
                fVideo->push(packet);
            }
            av_packet_unref(packet);
        } else if(ret == AVERROR_EOF) {
            break;
        }
    }
    while (isPlaying) {
        if(fAudio->p_queue.empty() && fVideo->p_queue.empty()) {
            break;
        }
        av_usleep(10 * 1000);
    }
    pthread_exit(0);
}

JNIEXPORT void JNICALL
Java_com_andon_colbert_ffplayer_FFPlayer_display(JNIEnv *env, jobject instance, jobject surface) {
    window = ANativeWindow_fromSurface(env, surface);
    LOG_I("window: %p", window);
}

JNIEXPORT void JNICALL
Java_com_andon_colbert_ffplayer_FFPlayer_release(JNIEnv *env, jobject instance) {
    if(isPlaying) {
        isPlaying = 0;
        pthread_join(p_tid, 0);
    }
    if (fAudio) {
        fAudio->release();
        delete fAudio;
    }
    if (fVideo) {
        fVideo->release();
        delete fVideo;
    }
    if(frtCtx) {
        avformat_close_input(&frtCtx);
    }
}


